﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using System.Data;
using System.IO;
using System.Xml.Linq;

namespace com.sharepointutils.application
{
    public class SharePointUtilities
    {

        #region WIKI Functions

        public static void uploadWikiPage(String url, System.Net.NetworkCredential cred, String listTitle, string documentName, String html, String column)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ctx.Load(list);
                    ctx.Load(list.RootFolder);
                    ctx.ExecuteQuery();
                    String relativeurl = list.RootFolder.ServerRelativeUrl + "/" + documentName;
                    Microsoft.SharePoint.Client.File f = list.RootFolder.Files.AddTemplateFile(relativeurl, TemplateFileType.WikiPage);

                    ListItem listItem = f.ListItemAllFields;
                    listItem["WikiField"] = html;
                    listItem["Documentation_x0020_Type"] = column;
                    listItem.Update();
                    ctx.ExecuteQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
        #endregion

        #region Folder Functions

        public static Folder createFolderPath(String url, System.Net.NetworkCredential cred, Folder currentFolder, String path)
        {
            Folder folder = null;
            if (!String.IsNullOrEmpty(path))
            {
                String[] paths = path.Halve("/");
                if (!String.IsNullOrEmpty(paths[0]))
                {
                    folder = getFolder(url, cred, currentFolder.ServerRelativeUrl + "/" + paths[0]);
                    if (folder == null)
                    {
                        using (ClientContext ctx = new ClientContext(url))
                        {
                            ctx.Credentials = cred;
                            Folder below = ctx.Web.GetFolderByServerRelativeUrl(currentFolder.ServerRelativeUrl);
                            ctx.Load(below);
                            ctx.ExecuteQuery();
                            folder = below.Folders.Add(paths[0]);
                            ctx.ExecuteQuery();
                        }
                        folder = getFolder(url, cred, currentFolder.ServerRelativeUrl + "/" + paths[0]);
                        if (!String.IsNullOrEmpty(paths[1]))
                        {
                            folder = createFolderPath(url, cred, folder, paths[1]);
                        }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(paths[1]))
                        {
                            folder = createFolderPath(url, cred, folder, paths[1]);
                        }
                    }
                }
                else
                {
                    folder = currentFolder;
                }
            }
            else
            {
                folder = currentFolder;
            }
            return folder;
        }


        public static Folder getFolder(String url, System.Net.NetworkCredential cred, String serverRelativeURL)
        {
            Folder returnFolder;
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    returnFolder = ctx.Web.GetFolderByServerRelativeUrl(serverRelativeURL);
                    ctx.Load(returnFolder);
                    ctx.ExecuteQuery();
                }
            }
            catch
            {
                returnFolder = null;
            }
            return returnFolder;
        }

        #endregion

        #region Content Type Functions


        public static ContentType[] GetSiteContentTypes(String url, System.Net.NetworkCredential cred)
        {
            ContentType[] returnValue;
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                ContentTypeCollection contentTypes = ctx.Web.ContentTypes;
                ctx.Load(contentTypes);
                ctx.ExecuteQuery();
                returnValue = contentTypes.ToArray();
            }
            return returnValue;
        }


        public static List<ContentType> get(String url, System.Net.NetworkCredential cred, String listTitle)
        {
            List<ContentType> contentTypeList = new List<ContentType>();
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ContentTypeCollection contentTypes = list.ContentTypes;
                    ctx.Load(contentTypes);
                    ctx.ExecuteQuery();
                    contentTypeList.AddRange(contentTypes.ToList());
                }
            }
            catch
            {

            }
            return contentTypeList;
        }

        public static Boolean UpdateContentType(String url, System.Net.NetworkCredential cred, String listTitle, ContentType oldContentType, Dictionary<String, object> properties)
        {
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ContentType contentType = list.ContentTypes.GetById(oldContentType.Id.ToString());

                    foreach (var p in properties)
                    {
                        contentType.GetType().GetProperty(p.Key).SetValue(contentType, p.Value, null);
                    }
                    contentType.Update(false);
                    ctx.ExecuteQuery();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }

        #endregion

        #region Document Set Functions

        public static String createDocumentSet(String siteURL, String documentListName, System.Net.NetworkCredential cred, string docSetContentTypeName, String documentSetName, String folderUrl, Dictionary<String, object> properties)
        {
            using (ClientContext clientContext = new ClientContext(siteURL))
            {
                clientContext.Credentials = cred;
                List existingList = clientContext.Web.Lists.GetByTitle(documentListName);
                try
                {
                    Web web = clientContext.Web;
                    ContentTypeCollection listContentTypes = existingList.ContentTypes;
                    clientContext.Load(existingList);
                    clientContext.Load(existingList.RootFolder);
                    clientContext.Load(listContentTypes);
                    var result = clientContext.LoadQuery(listContentTypes.Where(c => c.Name == docSetContentTypeName));
                    clientContext.ExecuteQuery();
                    ContentType targetDocumentSetContentType = result.FirstOrDefault();
                    ListItemCreationInformation newItemInfo = new ListItemCreationInformation();
                    newItemInfo.UnderlyingObjectType = FileSystemObjectType.Folder;
                    newItemInfo.LeafName = documentSetName;

                    if (!String.IsNullOrWhiteSpace(folderUrl))
                    {
                        newItemInfo.FolderUrl = String.Format("{0}/{1}", existingList.RootFolder.ServerRelativeUrl, folderUrl);
                    }

                    ListItem newListItem = existingList.AddItem(newItemInfo);
                    newListItem["ContentTypeId"] = targetDocumentSetContentType.Id.ToString();
                    newListItem["Title"] = documentSetName;

                    foreach (var prop in properties)
                    {
                        newListItem[prop.Key] = prop.Value;
                    }

                    newListItem.Update();
                    clientContext.ExecuteQuery();

                    List<ContentTypeId> allowedContentTypes = null;
                    ////get the allowed content types from the document set’s schema
                    if (targetDocumentSetContentType != null)
                    {
                        allowedContentTypes = GetAllowedContentTypes(targetDocumentSetContentType.SchemaXml, listContentTypes, clientContext);
                    }
                    //get the new document set created as folder in order
                    //to access the UniqueContentTypeOrder property
                    string targetDocSetUrl = !String.IsNullOrWhiteSpace(folderUrl) ? String.Format("{0}/{1}/{2}", existingList.RootFolder.ServerRelativeUrl, folderUrl, documentSetName) : existingList.RootFolder.ServerRelativeUrl + "/" + documentSetName;
                    Folder folder = web.GetFolderByServerRelativeUrl(targetDocSetUrl);
                    clientContext.Load(folder);
                    clientContext.Load(folder, f => f.UniqueContentTypeOrder);
                    clientContext.ExecuteQuery();

                    if (allowedContentTypes != null)
                    {
                        if (allowedContentTypes.Count != 0)
                        {
                            //set the document set’s allowed content types using the UniqueContentTypeOrder property
                            folder.UniqueContentTypeOrder = allowedContentTypes;
                            folder.Update();
                            clientContext.ExecuteQuery();
                        }
                    }
                    return folder.ServerRelativeUrl;
                }
                catch (Exception ex)
                {
                    throw new Exception("Could not create document set. (Name: " + documentSetName + " List: " + documentListName + " Content Type: " + docSetContentTypeName + ") Error: " + ex.Message, ex); ;
                }
            }
        }
        #endregion

        #region ListItem Functions

        public static ListItemCollection getAllListItems(String url, String listTitle, System.Net.NetworkCredential cred)
        {
            ListItemCollection collection = null;
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    List existingList = ctx.Web.Lists.GetByTitle(listTitle);
                    CamlQuery q = new CamlQuery();
                    q.ViewXml = "<View><RowLimit>5000</RowLimit></View>";
                    collection = existingList.GetItems(q);
                    ctx.Load(collection);
                    ctx.ExecuteQuery();
                }
            }
            catch //(Exception ex)
            {
                collection = null;
            }
            return collection;
        }

        public static ListItemCollection getAllListItems(String url, String listTitle, String query, System.Net.NetworkCredential cred)
        {
            ListItemCollection collection = null;
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                List existingList = ctx.Web.Lists.GetByTitle(listTitle);
                CamlQuery q = new CamlQuery();
                q.ViewXml = query;
                collection = existingList.GetItems(q);
                ctx.Load(collection);
                ctx.ExecuteQuery();
            }
            return collection;
        }

        public static List<ListItem> getFullCollectionListItems(String url, String listTitle, String query, System.Net.NetworkCredential cred)
        {
            List<ListItem> fullCollection = new List<ListItem>();
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                ctx.RequestTimeout = -1;
                List list = ctx.Web.Lists.GetByTitle(listTitle);
                CamlQuery q = new CamlQuery();

                if(!Query.ContainsElement(query,"RowLimit"))
                {
                    query = Query.InsertElement(query, "RowLimit", "2000");
                }

                q.ViewXml = query;

                do
                {
                    ListItemCollection collection = list.GetItems(q);
                    ctx.Load(collection);
                    ctx.ExecuteQuery();
                    fullCollection.AddRange(collection);
                    q.ListItemCollectionPosition = collection.ListItemCollectionPosition;
                } while (q.ListItemCollectionPosition != null);
            }
            return fullCollection;
        }

        public static DataTable getAllListItemsReturnDataTable(String url, String listTitle, String query, System.Net.NetworkCredential cred)
        {
            ListItemCollection collection = getAllListItems(url, listTitle, query, cred);
            return getDataTable(collection);
        }

        public static DataTable getFullListItemsReturnDataTable(String url, String listTitle, String query, System.Net.NetworkCredential cred)
        {
            List<ListItem> collection = getFullCollectionListItems(url, listTitle, query, cred);
            return getDataTable(collection);
        }

        public static DataTable getDataTable(ListItemCollection collection)
        {
            DataTable dt = new DataTable();


            if (collection == null || collection.Count == 0)
            {
                throw new Exception("Collection is Empty");
            }

            foreach (var field in collection[0].FieldValues)
            {
                dt.Columns.Add(field.Key);
            }

            foreach (ListItem item in collection)
            {
                List<object> parameters = new List<object>();
                foreach (KeyValuePair<String, object> f in item.FieldValues)
                {
                    parameters.Add(getStringValueOfField(f));
                }
                dt.Rows.Add(parameters.ToArray());
            }

            return dt;
        }

        public static DataTable getDataTable(List<ListItem> collection)
        {
            DataTable dt = new DataTable();
            if (collection == null || collection.Count == 0)
            {
                throw new Exception("Collection is Empty");
            }

            foreach (var field in collection[0].FieldValues)
            {
                dt.Columns.Add(field.Key);
            }

            foreach (ListItem item in collection)
            {
                List<object> parameters = new List<object>();
                foreach (KeyValuePair<String, object> f in item.FieldValues)
                {
                    parameters.Add(getStringValueOfField(f));
                }
                dt.Rows.Add(parameters.ToArray());
            }

            return dt;
        }

        public static Stream DownloadListItem(string url, ListItem item)
        {
            if (item != null)
            {
                using (ClientContext clientContext = new ClientContext(url))
                {
                    FileInformation fInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext,
                        item["FileRef"].ToString());
                    return fInfo.Stream;
                }

            }
            return null;
        }

        public static void uploadDocument(String url, String folderServerRelativeURL, System.Net.NetworkCredential cred, string documentName, Stream documentStream)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                ctx.RequestTimeout = -1;
                Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, folderServerRelativeURL + "/" + documentName, documentStream, false);
            }
        }

        public static void uploadDocument(String url, System.Net.NetworkCredential cred, String listTitle, string documentName, Stream documentStream)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                ctx.RequestTimeout = -1;
                List list = ctx.Web.Lists.GetByTitle(listTitle);
                ctx.Load(list);
                ctx.Load(list.RootFolder);
                ctx.ExecuteQuery();
                Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, list.RootFolder.ServerRelativeUrl + "/" + documentName, documentStream, false);
            }
        }

        public static void uploadDocument(String url, System.Net.NetworkCredential cred, String listTitle, string documentName, Stream documentStream, Dictionary<String, object> properties)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                ctx.RequestTimeout = -1;
                List list = ctx.Web.Lists.GetByTitle(listTitle);
                ctx.Load(list);
                ctx.Load(list.RootFolder);
                ctx.ExecuteQuery();
                String relativeURL = list.RootFolder.ServerRelativeUrl + "/" + documentName;

                Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, relativeURL, documentStream, false);


                Microsoft.SharePoint.Client.File file = ctx.Web.GetFileByServerRelativeUrl(relativeURL);
                ctx.Load(file.ListItemAllFields);
                ctx.ExecuteQuery();

                //QueryBuilder qb = new QueryBuilder();
                //qb.Scope = "RecursiveALL";
                //qb.RowLimit = 1;
                //qb.Condition = new QueryCondition("FileLeafRef", documentName, ComparisonOperator.Eq);

                ListItem listItem = list.GetItemById(file.ListItemAllFields.Id);//GetItems(qb.toCamlQuery());
                ctx.Load(listItem);
                ctx.ExecuteQuery();

                foreach (var property in properties)
                {
                    listItem[property.Key] = property.Value;
                }
                listItem.Update();
                ctx.ExecuteQuery();
            }
        }

        public static String uploadDocument(String url, System.Net.NetworkCredential cred, String listTitle, String path, string documentName, byte[] bytes, Boolean overwrite)
        {
            String filePath = "";
            using (ClientContext ctx = new ClientContext(url))
            {
                using (MemoryStream documentStream = new MemoryStream(bytes))
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ctx.Load(list);
                    ctx.Load(list.RootFolder);
                    ctx.ExecuteQuery();
                    Folder folder = createFolderPath(url, cred, list.RootFolder, path);
                    filePath = folder.ServerRelativeUrl + "/" + documentName;
                    Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, filePath, documentStream, overwrite);
                }
            }
            return filePath;
        }

        public static void updateListItem(String url, System.Net.NetworkCredential cred, String listTitle, string name, Dictionary<String, object> props)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    CamlQuery q = new CamlQuery();

                    q.ViewXml = @"<View><Query><Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='Text'>" + name + @"</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>";

                    ListItemCollection collection = list.GetItems(q);
                    ctx.Load(collection);
                    ctx.ExecuteQuery();

                    if (collection.Count > 0)
                    {
                        ListItem listItem = collection[0];

                        foreach (var p in props)
                        {
                            listItem[p.Key] = p.Value;
                        }
                        listItem.Update();
                        ctx.ExecuteQuery();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public static void updateListItem(String url, System.Net.NetworkCredential cred, String listTitle, int id, Dictionary<String, object> props)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ListItem listItem = list.GetItemById(id);
                    ctx.Load(listItem);
                    ctx.ExecuteQuery();

                    if (listItem != null)
                    {
                        foreach (var p in props)
                        {
                            listItem[p.Key] = p.Value;
                        }
                        listItem.Update();
                        ctx.ExecuteQuery();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public static int updateListItems(String url, System.Net.NetworkCredential cred, String listTitle, String query, Dictionary<String, object> props)
        {
            int count = 0;
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    CamlQuery q = new CamlQuery();
                    q.ViewXml = query;

                    do
                    {
                        ListItemCollection collection = list.GetItems(q);
                        ctx.Load(collection);
                        ctx.ExecuteQuery();

                        foreach (ListItem i in collection)
                        {
                            foreach (var p in props)
                            {
                                i[p.Key] = p.Value;
                            }
                            i.Update();
                            count++;
                        }
                        ctx.ExecuteQuery();
                        q.ListItemCollectionPosition = collection.ListItemCollectionPosition;
                    } while (q.ListItemCollectionPosition != null);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return count;
        }

        public static int updateListItems(String url, System.Net.NetworkCredential cred, String listTitle, String query, Dictionary<String, object> props, String javascript)
        {
            Javascript.JavascriptEngine engine = new Javascript.JavascriptEngine();
            engine.CompileFunction(javascript);
            int count = 0;
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    CamlQuery q = new CamlQuery();
                    q.ViewXml = query;

                    do
                    {
                        ListItemCollection collection = list.GetItems(q);
                        ctx.Load(collection);
                        ctx.ExecuteQuery();

                        foreach (ListItem i in collection)
                        {
                            foreach (var p in props)
                            {
                                if (p.Value.ToString() == "Javascript Function")
                                {
                                    String[] array = i[p.Key] as String[];
                                    String[] temp = engine.JSArrayToStringArray(engine.RunFunction(engine.toJSVariable(array)));
                                    i[p.Key] = temp;   
                                }
                                else
                                {
                                    i[p.Key] = p.Value;
                                }
                            }
                            i.Update();
                            count++;
                        }
                        ctx.ExecuteQuery();
                        q.ListItemCollectionPosition = collection.ListItemCollectionPosition;
                    } while (q.ListItemCollectionPosition != null);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return count;
        }

        public static int createListItem(String url, String listTitle, Dictionary<String, object> props, System.Net.NetworkCredential cred)
        {
            int id = -1;
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);

                    ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
                    itemCreateInfo.LeafName = "";
                    ListItem listItem = list.AddItem(itemCreateInfo);

                    foreach (var p in props)
                    {
                        listItem[p.Key] = p.Value;
                    }
                    listItem.Update();
                    ctx.ExecuteQuery();
                    id = listItem.Id;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return id;
        }

        public static List<AttachmentsInfo> DownloadAttachedFilesFromListItem(string siteUrl, string listName, int itemId, System.Net.NetworkCredential cred)
        {
            List<AttachmentsInfo> files = new List<AttachmentsInfo>();
            using (ClientContext ctx = new ClientContext(siteUrl))
            {
                ctx.Credentials = cred;
                List list = ctx.Web.Lists.GetByTitle(listName);
                ctx.Load(list, l => l.RootFolder.ServerRelativeUrl);
                ctx.Load(ctx.Site, s => s.Url);
                ctx.ExecuteQuery();

                // get the item's attachments folder 
                Folder attFolder = ctx.Web.GetFolderByServerRelativeUrl(list.RootFolder.ServerRelativeUrl + "/Attachments/" + itemId);
                FileCollection filesCollection = attFolder.Files;

                ctx.Load(attFolder);
                ctx.Load(filesCollection);
                ctx.ExecuteQuery();

                foreach (Microsoft.SharePoint.Client.File f in filesCollection)
                {
                    ctx.Load(f);
                    ctx.ExecuteQuery();
                    FileInformation fileInformation = Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx, f.ServerRelativeUrl);
                    IList<byte> content = new List<byte>();
                    int b;
                    while ((b = fileInformation.Stream.ReadByte()) != -1)
                    {
                        content.Add((byte)b);
                    }
                    fileInformation.Stream.Close();
                    files.Add(new AttachmentsInfo(content.ToArray(), f.Name));
                }
            }
            return files;
        }

        public static void AttachFilesToListItem(string siteUrl, string listName, int itemId, System.Net.NetworkCredential cred, List<AttachmentsInfo> files)
        {
            foreach (AttachmentsInfo f in files)
            {
                String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                    "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                                      "<soap:Body>" +
                                        "<AddAttachment xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">" +
                                          "<listName>" + listName + "</listName>" +
                                          "<listItemID>" + itemId + "</listItemID>" +
                                          "<fileName>" + f.FileName + "</fileName>" +
                                          "<attachment>" + Convert.ToBase64String(f.Bytes) + "</attachment>" +
                                        "</AddAttachment>" +
                                      "</soap:Body>" +
                                    "</soap:Envelope>";
                String result = SharePointSOAPRequest.Run(siteUrl, "http://schemas.microsoft.com/sharepoint/soap/AddAttachment", cred, message);
            }
        }

        public static void DeleteAttachedFileFromListItem(string siteUrl, string webName, int itemId, string attachmentFileName, string listName)
        {
            using (ClientContext clientContext = new ClientContext(siteUrl))
            {
                //http://siteurl/lists/[listname]/attachments/[itemid]/[filename]
                string attachmentPath = string.Format("/{0}/lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(attachmentFileName));
                var file = clientContext.Web.GetFileByServerRelativeUrl(attachmentPath);
                file.DeleteObject();
                clientContext.ExecuteQuery();
            }
        }
        #endregion

        #region List Functions

        public static List<String> getContentTypes(String url, String listTitle, System.Net.NetworkCredential cred)
        {
            List<String> list = new List<string>();
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    List existingList = ctx.Web.Lists.GetByTitle(listTitle);
                    ContentTypeCollection listContentTypes = existingList.ContentTypes;
                    ctx.Load(listContentTypes);
                    ctx.ExecuteQuery();

                    foreach (ContentType c in listContentTypes)
                    {
                        list.Add(c.Name);
                    }
                }
            }
            catch
            {
                list.Add("Failed to load content types");
            }
            return list;
        }

        //public static List<FieldDropdownChoice> getListColumns(String url, System.Net.NetworkCredential cred, String listTitle)
        //{
        //    List<FieldDropdownChoice> fields = new List<FieldDropdownChoice>();
        //    using (ClientContext ctx = new ClientContext(url))
        //    {
        //        try
        //        {
        //            ctx.Credentials = cred;
        //            ctx.RequestTimeout = -1;
        //            List list = ctx.Web.Lists.GetByTitle(listTitle);
        //            ctx.Load(list);
        //            ctx.Load(list.Fields);
        //            ctx.ExecuteQuery();

        //            foreach (Field f in list.Fields)
        //            {
        //                fields.Add(new FieldDropdownChoice (f));
        //            }
        //        }
        //        catch (Exception ex)
        //        {
        //            throw ex;
        //        }
        //    }
        //    return fields;
        //}

        public static void AddColumn(String url, System.Net.NetworkCredential cred, String listTitle, String fieldSchema)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    FieldCollection collField = list.Fields;
                    Field f = collField.AddFieldAsXml(fieldSchema, false, AddFieldOptions.DefaultValue);
                    //ctx.Load(collField);
                    ctx.ExecuteQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public static BaseType GetListType(String url, System.Net.NetworkCredential cred, String listTitle)
        {
            BaseType type = BaseType.None;
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ctx.Load(list);
                    ctx.ExecuteQuery();
                    type = list.BaseType;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return type;
        }

        public static List<KeyValuePair<String, String>> getListColumnsbyDictionary(String url, System.Net.NetworkCredential cred, String listTitle)
        {
            List<KeyValuePair<String, String>> fields = new List<KeyValuePair<String, String>>();
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    ctx.RequestTimeout = -1;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    ctx.Load(list);
                    ctx.Load(list.Fields);
                    ctx.ExecuteQuery();

                    foreach (Field f in list.Fields)
                    {
                        fields.Add(new KeyValuePair<String, String>(f.Title, f.InternalName));
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return fields;
        }

        private static List<ContentTypeId> GetAllowedContentTypes(string listSchemaXml, ContentTypeCollection listContentTypes, ClientContext context)
        {
            List<ContentTypeId> allowableContentTypeIds = new List<ContentTypeId>();
            try
            {
                List<string> schemaContentypeIds = new List<string>();

                XNamespace act = "http://schemas.microsoft.com/office/documentsets/allowedcontenttypes";
                XDocument document = XDocument.Parse(listSchemaXml);
                var result = from e in document.Descendants().Elements("XmlDocuments").Elements("XmlDocument").Elements(act + "AllowedContentTypes").Elements("AllowedContentType").Attributes("id") select e.Value;
                if (result != null && result.Count() > 0)
                    schemaContentypeIds = result.ToList<string>();
                foreach (string schemaContentTypeId in schemaContentypeIds)
                {
                    foreach (ContentType listContentType in listContentTypes)
                    {
                        context.Load(listContentType.Parent);
                        context.ExecuteQuery();

                        if (listContentType.Parent.Id.ToString() == schemaContentTypeId)
                        {
                            allowableContentTypeIds.Add(listContentType.Id);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return allowableContentTypeIds;
        }

        public static void copyList(String siteURLFrom, System.Net.NetworkCredential credFrom, String siteURLTo, System.Net.NetworkCredential credTo, String listName)
        {
            using (ClientContext ctx = new ClientContext(siteURLFrom))
            {
                ctx.Credentials = credFrom;
                List listFrom = ctx.Web.Lists.GetByTitle(listName);
                ctx.Load(listFrom);
                ctx.Load(listFrom.Fields);
                ctx.ExecuteQuery();
                createList(siteURLTo, credTo, listName, listFrom.Description, listFrom.BaseTemplate, listFrom.Fields);
            }
        }

        public static void createList(String siteURL, System.Net.NetworkCredential cred, String listName, String description, int type, FieldCollection fields)
        {
            List newList = null;
            using (ClientContext ctx = new ClientContext(siteURL))
            {
                ctx.Credentials = cred;

                ListCreationInformation lc = new ListCreationInformation();
                lc.Title = listName;
                lc.Description = description;
                lc.TemplateType = type;

                newList = ctx.Web.Lists.Add(lc);
                ctx.ExecuteQuery();
                ctx.Load(newList.Fields);
                ctx.ExecuteQuery();

                List<Guid> guids = new List<Guid>();

                foreach (Field nf in newList.Fields)
                {
                    guids.Add(nf.Id);
                }

                foreach (Field f in fields)
                {
                    if (f.Hidden == false && !guids.Contains(f.Id) && f.TypeAsString != "Computed" && f.TypeAsString != "WorkflowStatus" && f.TypeAsString != "Calculated")
                    {
                        newList.Fields.AddFieldAsXml(f.SchemaXml, true, AddFieldOptions.DefaultValue);
                    }
                }
                newList.Update();
                ctx.ExecuteQuery();

                foreach (Field f in fields)
                {
                    if (f.Hidden == false && !guids.Contains(f.Id) && (f.TypeAsString == "Computed" || f.TypeAsString == "Calculated"))
                    {
                        newList.Fields.AddFieldAsXml(f.SchemaXml, true, AddFieldOptions.DefaultValue);
                    }
                }
                newList.Update();
                ctx.ExecuteQuery();
            }
        }

        public static void createList(String siteURL, System.Net.NetworkCredential cred, String listName, String description, int type)
        {
            List newList = null;
            using (ClientContext ctx = new ClientContext(siteURL))
            {
                ctx.Credentials = cred;

                ListCreationInformation lc = new ListCreationInformation();
                lc.Title = listName;
                lc.Description = description;
                lc.TemplateType = type;

                newList = ctx.Web.Lists.Add(lc);
                ctx.ExecuteQuery();
            }
        }

        public static void deleteList(String siteURL, System.Net.NetworkCredential cred, String listName)
        {
            using (ClientContext ctx = new ClientContext(siteURL))
            {
                ctx.Credentials = cred;
                List list = ctx.Web.Lists.GetByTitle(listName);
                list.DeleteObject();
                ctx.ExecuteQuery();
            }
        }

        public static String getListRootFolderServerRelativeURL(String siteURL, String listName, System.Net.NetworkCredential cred)
        {
            String url = "";
            using (ClientContext ctx = new ClientContext(siteURL))
            {
                ctx.Credentials = cred;
                List documentList = ctx.Web.Lists.GetByTitle(listName);
                ctx.Load(documentList.RootFolder);
                ctx.ExecuteQuery();
                url = documentList.RootFolder.ServerRelativeUrl;
            }
            return url;
        }

        #endregion

        #region File Functions

        public static void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[8 * 1024];
            int len;
            while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, len);
            }
        }

        public static KeyValuePair<String, byte[]> DownloadFile(String URL, System.Net.NetworkCredential cred)
        {
            KeyValuePair<string, byte[]> file;
            using (System.Net.WebClient client = new System.Net.WebClient())
            {
                client.Credentials = cred;
                byte[] bytes = client.DownloadData(URL);
                file = new KeyValuePair<string, byte[]>(Path.GetFileName(URL), bytes);
            }
            return file;
        }

        public static byte[] getBytes(Stream stream)
        {
            byte[] contents = null;
            try
            {
                contents = new byte[stream.Length];
                stream.Read(contents, 0, (int)stream.Length);
                stream.Close();
            }
            catch
            {
                contents = null;
            }
            return contents;
        }
        #endregion

        #region Site Functions
        public static List<String> getLists(String url, System.Net.NetworkCredential cred)
        {
            List<String> list = new List<string>();
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    Web site = ctx.Web;
                    ctx.Load(site.Lists);
                    ctx.ExecuteQuery();

                    foreach (List l in site.Lists)
                    {
                        list.Add(l.Title);
                    }
                }
            }
            catch //(Exception ex)
            {
                list.Add("Failed to load site");
            }
            return list;
        }

        public static List<List> getListsWithListInformation(String url, System.Net.NetworkCredential cred)
        {
            List<List> list = new List<List>();
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                Web site = ctx.Web;
                ctx.Load(site.Lists, lists => lists.IncludeWithDefaultProperties(lt => lt.Id, lt => lt.SchemaXml, lt => lt.Views, lt => lt.Fields, lt => lt.ContentTypes));
                ctx.ExecuteQuery();

                foreach (List spList in site.Lists)
                {
                    list.Add(spList);
                }
            }
            return list;
        }

        public static String getSiteName(String url, System.Net.NetworkCredential cred)
        {
            String siteName = "";
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    Web web = ctx.Web;
                    ctx.Load(web);
                    ctx.ExecuteQuery();
                    siteName = web.Title;
                }
            }
            catch
            {
                siteName = "";
            }
            return siteName;
        }

        public static SiteInformation getSiteInformation(String url, System.Net.NetworkCredential cred)
        {
            SiteInformation site = null;
            try
            {
                using (ClientContext ctx = new ClientContext(url))
                {
                    ctx.Credentials = cred;
                    Web web = ctx.Web;
                    ctx.Load(web);
                    ctx.ExecuteQuery();
                    site = new SiteInformation(web.Title, web.Id, url, cred);
                }
            }
            catch
            {
                site = null;
            }
            return site;
        }

        public static String getSiteName(SiteInformation connection)
        {
            String siteName = "";
            try
            {
                using (ClientContext ctx = new ClientContext(connection.URL))
                {
                    ctx.Credentials = connection.Credentials;
                    Web web = ctx.Web;
                    ctx.Load(web);
                    ctx.ExecuteQuery();
                    siteName = web.Title;
                }
            }
            catch
            {
                siteName = "";
            }
            return siteName;
        }

        public static SiteInformation[] getSubsites(String url, System.Net.NetworkCredential cred)
        {
            List<SiteInformation> sites = new List<SiteInformation>();
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                WebCollection subsites = ctx.Web.Webs;
                ctx.Load(subsites);
                ctx.ExecuteQuery();

                Uri serveraddress = new Uri(url);

                foreach (Web w in subsites)
                {
                    sites.Add(new SiteInformation(w.Title, w.Id, serveraddress.Scheme + "://" + serveraddress.Host + w.ServerRelativeUrl, cred));
                }
            }
            return sites.ToArray();
        }

        public static SiteInformation[] GetALLSubsites(String url, System.Net.NetworkCredential cred)
        {
            List<SiteInformation> sites = new List<SiteInformation>();
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                Web site = ctx.Web;
                WebCollection subsites = ctx.Web.Webs;
                ctx.Load(site);
                ctx.Load(subsites);
                ctx.ExecuteQuery();

                Uri serveraddress = new Uri(url);
                String baseURL = serveraddress.Scheme + "://" + serveraddress.Host;

                sites.Add(new SiteInformation(site.Title, site.Id, baseURL + site.ServerRelativeUrl, cred));

                foreach (Web w in subsites)
                {
                    sites.AddRange(GetALLSubsites(ctx, w, baseURL));
                }
            }
            return sites.ToArray();
        }

        public static SiteInformation[] GetALLSubsites(ClientContext context, Web parentSite, String baseURL)
        {
            List<SiteInformation> sites = new List<SiteInformation>();
            WebCollection subsites = parentSite.Webs;
            sites.Add(new SiteInformation(parentSite.Title, parentSite.Id, baseURL + parentSite.ServerRelativeUrl, null));
            context.Load(subsites);
            context.ExecuteQuery();
            foreach (Web w in subsites)
            {           
                sites.AddRange(GetALLSubsites(context, w, baseURL));
            }
            return sites.ToArray();
        }

        #endregion

        #region Field Functions

        public static Field[] GetSiteColumns(String url, System.Net.NetworkCredential cred)
        {
            Field[] returnValue;
            using (ClientContext ctx = new ClientContext(url))
            {
                ctx.Credentials = cred;
                FieldCollection fields = ctx.Web.Fields;
                ctx.Load(fields);
                ctx.ExecuteQuery();
                returnValue = fields.ToArray();
            }
            return returnValue;
        }


        public static String getStringValueOfField(KeyValuePair<String, object> field)
        {
            String value = null;
            if (field.Value != null)
            {
                switch (field.Value.GetType().Name)
                {
                    case "FieldUserValue":
                        FieldUserValue FieldUserValuetemp = field.Value as FieldUserValue;
                        value = FieldUserValuetemp.LookupValue;
                        break;
                    case "FieldLookupValue":
                        FieldLookupValue FieldLookupValuetemp = field.Value as FieldLookupValue;
                        value = FieldLookupValuetemp.LookupValue;
                        break;
                    case "FieldUrlValue":
                        FieldUrlValue FieldUrlValuetemp = field.Value as FieldUrlValue;
                        value = FieldUrlValuetemp.Url;
                        break;
                    case "String[]":
                        String[] stringArray = field.Value as String[];
                        value = String.Join(";",stringArray);
                        break;
                    //case "FieldUserValue[]":
                    //    FieldUserValue[] fieldUserValue = field.Value as FieldUserValue;
                    //    value = FieldUrlValuetemp.Url;
                    //    break;
                    default:
                        value = field.Value.ToString();
                        break;
                }
            }
            return value;
        }

        public static void DeleteField(String url, System.Net.NetworkCredential cred, String listTitle, Field field)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    Field f = list.Fields.GetById(field.Id);
                    ctx.Load(f);
                    ctx.ExecuteQuery();

                    if (f != null)
                    {
                        f.ReadOnlyField = false;
                        f.Hidden = false;
                        f.Update();
                        ctx.ExecuteQuery();
                        f.DeleteObject();
                        ctx.ExecuteQuery();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }


        public static void UpdateField(String url, System.Net.NetworkCredential cred, String listTitle, Field field, Dictionary<String, object> properties)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    Field f = list.Fields.GetById(field.Id);
                    ctx.Load(f);
                    ctx.ExecuteQuery();

                    foreach (var p in properties)
                    {
                        f.GetType().GetProperty(p.Key).SetValue(f, p.Value, null);
                    }
                    f.Update();
                    ctx.ExecuteQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        #endregion

        #region View Functions

        public static void updateView(String url, System.Net.NetworkCredential cred, String listTitle, Guid viewGuid, Dictionary<String, object> properties)
        {
            using (ClientContext ctx = new ClientContext(url))
            {
                try
                {
                    ctx.Credentials = cred;
                    List list = ctx.Web.Lists.GetByTitle(listTitle);
                    View view = list.GetView(viewGuid);
                    ctx.Load(view);
                    ctx.ExecuteQuery();

                    if (view != null)
                    {

                        foreach (var p in properties)
                        {
                            view.GetType().GetProperty(p.Key).SetValue(view, p.Value, null);
                        }
                        view.Update();
                        ctx.ExecuteQuery();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        #endregion
    }
}
